#Функции формирующие словари баз, кубов, измерений, элементов
#Функция convert response
#Функции: extract, extract_nda, dice_nda
#Функции: strlist и другие вспомогательные функции

"""This module contains python manipulators for palo objects"""

#import of the following packages used for xlsgen function of the class list of lists (lol)
#will be commented along with the function for python3 version

#impots for lol class
#import xlrd, xlwt

#imports for sympy objects
#from sympy import *
from __future__ import division
from sympy.tensor import IndexedBase, Idx
from sympy import symbols

#imports for other classes
from datetime import datetime
from copy import deepcopy
from pypalo.basic import default
from pypalo.tools import sublist, strlist, arealize, meter, subdata, pacecounter, headfiller

from pypalo.requests.server import query as server
from pypalo.requests.database import query as database
from pypalo.requests.dimension import query as dimension
from pypalo.requests.element import query as element
from pypalo.requests.cube import query as cube
from pypalo.requests.cell import query as cell
from pypalo.requests.event import query as event
from pypalo.requests.rules import query as rules
from pypalo.requests.svs import query as svs

#query dictionary
query={}
query["server"]=server
query["database"]=database
query["dimension"]=dimension
query["element"]=element
query["cube"]=cube
query["cell"]=cell
query["event"]=event
query["rules"]=rules
query["svs"]=svs

class host:
	"""This is a host manipulator"""
	#beginning of class suite
	#init function
	def __init__(self, host=default["host"], port=default["port"]):
		self.host=host
		self.port=port
	
	#The following functions create class objects:
	def User(self, username=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"]):
		"""Function creates user class object"""
		#beginning of function suite
		#end of function suite
		return user(username, password, sid, timeinit, timeleft, self.host, self.port)
	
	#end of host class suite

class user(host):
	"""This is a user manipulator"""
	#beginning of class suite
	#init function
	def __init__(self, user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#call parent init function with self arguments
		super(__class__, self).__init__(host, port)
		#child methods
		self.user=user
		self.password=password
		self.sid=sid
		self.timeinit=timeinit
		self.timeleft=timeleft
		
		self.database=default["database"]
		self.dimension=default["dimension"]
		self.element=default["element"]
		self.cube=default["cube"]
		self.path=default["path"]
		self.rule=default["rule"]
	
	def state(self):
		"""This funtcion checks if sid is valid"""
		#beginning of function suite
		if self.sid and self.timeleft>(datetime.now()-self.timeinit).seconds:
			return True
		else:
			return False
		
	def newsid(self):
		"""This funtcion replaces old sid, timeinit, timeleft with new ones"""
		#beginning of function suite
		if self.state():
			self.disconnect()
			self.connect()
		else:
			self.connect()
		#end of function suite
		return
	
	def connect(self):
		"""This funtcion gets new sid"""
		#beginning of function suite
		self.sid=query["server"]["login"](self.host, self.port, user=self.user, password=self.password)[0][0]
		self.timeinit=datetime.now()
		self.timeleft=3595
		#end of function suite
		return

	def disconnect(self):
		"""This funtcion logouts and turns self.sid, self.timeinit, self.timeleft to None"""
		#beginning of function suite
		query["server"]["logout"](self.sid, self.host, self.port)
		self.sid=None
		self.timeinit=None
		self.timeleft=None
		#end of function suite
		return

	def getsid(self):
		"""This function validates sid, if not valid connects, finally returns self.sid"""
		#beginning of function suite
		if not self.state():
			self.connect()
		#end of function suite
		return self.sid

	#The following functions create class objects:
	def Server(self):
		"""Function creates server class object"""
		#beginning of function suite
		#end of function suite
		return server(self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Database(self, database_id=default["database"]):
		"""Function creates database class object"""
		#beginning of function suite
		database_id=database_id or self.database
		#end of function suite
		return database(database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Dimension(self, dimension_id=default["dimension"], database_id=default["database"]):
		"""Function creates dimension class object"""
		#beginning of function suite
		dimension_id=dimension_id or self.dimension
		database_id=database_id or self.database
		#end of function suite
		return dimension(dimension_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Element(self, element_id=default["element"], dimension_id=default["dimension"], database_id=default["database"]):
		"""Function creates element class object"""
		#beginning of function suite
		element_id=element_id or self.element
		dimension_id=dimension_id or self.dimension
		database_id=database_id or self.database
		#end of function suite
		return element(element_id, dimension_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Cube(self, cube_id=default["cube"], database_id=default["database"]):
		"""Function creates cube class object"""
		#beginning of function suite
		cube_id=cube_id or self.cube
		database_id=database_id or self.database
		#end of function suite
		return cube(cube_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Cell(self, path=default["path"], cube_id=default["cube"], database_id=default["database"]):
		"""Function creates cell class object"""
		#beginning of function suite
		path=path or self.path
		cube_id=cube_id or self.cube
		database_id=database_id or self.database
		#end of function suite
		return cell(path, cube_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Rules(self, rule=default["rule"], cube_id=default["cube"], database_id=default["database"]):
		"""Function creates rules class object"""
		#beginning of function suite
		rule=rule or self.rule
		cube_id=cube_id or self.cube
		database_id=database_id or self.database
		#end of function suite
		return rules(rule, cube_id, database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Svs(self):
		"""Function creates svs class object"""
		#beginning of function suite
		#end of function suite
		return svs(self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#end of user class suite

class server(user):
	"""This is a server manipulator"""
	#beginning of class suite
	
	#init function
	def __init__(self, user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		
	#The following functions wrap PALO API requests:
	def databases(self, **keywords):
		"""Function returns list of databases\nPositional arguments: None\nKeyword arguments: show_normal, show_system, show_user_info\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["databases"](self.getsid(), self.host, self.port, **keywords)

	def info(self):
		"""Function returns server info\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["info"](self.host, self.port)

	def license(self):
		"""Function returns server license\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["license"](self.host, self.port)

	def load(self):
		"""Function loads server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["load"](self.getsid(), self.host, self.port)

	def login(self, **keywords):
		"""Function returns sid\nPositional arguments: None\nKeyword arguments: user, password, extern_password\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["login"](self.host, self.port, **keywords)

	def logout(self, sid):
		"""Function logouts on server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["logout"](sid, self.host, self.port)

	def save(self):
		"""Function saves server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["save"](self.getsid(), self.host, self.port)

	def shutdown(self):
		"""Function shutdowns server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["server"]["shutdown"](self.getsid(), self.host, self.port)

	#The following functions create class objects:
	def Database(self, database_id=default["database"]):
		"""Function creates database class object"""
		#beginning of function suite
		#end of function suite
		return database(database_id, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#The following functions are server tools:
	def dictionary(self):
		"This function returns dictionary of server databases"
		#beginning of function suite
		databases=self.databases()
		result={}
		result['ids']={}
		result['names']={}
		for database in databases:
			result['ids'][database[0]]=database[1]
			result['names'][database[1]]=database[0]
		#end of function suite
		return result

	#end of server class suite

class database(user):
	"""This is a database manipulator"""
	#beginning of class suite
	
	#init function
	def __init__(self, database=default["database"], user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
	
	def cubes(self, database=None, **keywords):
		"""Function returns list of cubes\nPositional arguments: database=None\nKeyword arguments: show_normal, show_system, show_attribute, show_info, show_gputype\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["cubes"](database, self.getsid(), self.host, self.port, **keywords)
	
	#api requests:
	def create(self, new_name):
		"""Function creates a new database\nPositional arguments: new_name\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		#end of function suite
		return query["database"]["create"](new_name, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, database=None):
		"""Function destroys database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["destroy"](database, self.getsid(), self.host, self.port)

	def dimensions(self, database=None, **keywords):
		"""Function returns list of cubes\nPositional arguments: None\nKeyword arguments: show_normal, show_system, show_attribute, show_info, database=None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["dimensions"](database, self.getsid(), self.host, self.port, **keywords)

	def info(self, database=None):
		"""Function returns database info\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["info"](database, self.getsid(), self.host, self.port)
	
	def load(self, database=None):
		"""Function loads database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["load"](database, self.getsid(), self.host, self.port)

	def rename(self, new_name, database=None, **keywords):
		"""Function renames database\nPositional arguments: new_name, database=None\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["rename"](new_name, database, self.getsid(), self.host, self.port, **keywords)
		
	def save(self, database=None):
		"""Function saves database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["save"](database, self.getsid(), self.host, self.port)

	def unload(self, database=None):
		"""Function saves database\nPositional arguments: database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["database"]["unload"](database, self.getsid(), self.host, self.port)

	#The following functions create class objects:
	def Dimension(self, dimension_id=default["dimension"], database=None):
		"""Function creates dimension class object"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return dimension(dimension_id, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)
	
	def Cube(self, cube_id=default["cube"], database=None):
		"""Function creates cube class object"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return cube(cube_id, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	#The following functions are database tools:
	def dictionary(self, database=None, **keywords):
		"This function returns dictionary of database cubes and dimensions"
		#beginning of function suite
		database = database or self.database
		dimensions=self.dimensions(database, **keywords)
		cubes=self.cubes(database, **keywords)
		result={}
		result['dims']={'ids':{}}
		result['dims']['names']={}
		result['dims']['labels']={}
		result['cubes']={'ids':{}}
		result['cubes']['names']={}
		result['cubes']['labels']={}
		letters=[]
		for dimension in dimensions:
			#dictionary of ids to names
			result['dims']['ids'][dimension[0]]=dimension[1]
			#dictionary of names to ids
			result['dims']['names'][dimension[1]]=dimension[0]
			#dictionary of ids to labels for sympy Idx
			
			while letter not in letters:
				
				for word in dimension[1].split('_'):
					if word[0] not in letters:
						
						break
					name+=word[0].upper()+word[1:].lower()
				names+=[name]
		
		for cube in cubes:
			#dictionary of ids to names
			result['cubes']['ids'][cube[0]]=cube[1]
			#dictionary of names to ids
			result['cubes']['names'][cube[1]]=cube[0]
			#dictionary of ids to labels for sympy IndexedBase
			name=''
			for word in cube[1].split('_'):
				name+=word[0].upper()+word[1:].lower()
			result['cubes']['label'][cube[0]]=name
			
		#end of function suite
		return result

	#The following functions are database tools:
	def dim_labels(self, excluded=[]):
		#beginning of function suite
		"This function returns list of Idx objects for the database dimensions"
		dims=self.dimensions()
		result={'id':{},'label':{}}
		labels=[]
		for dim in dims:
			id = dim[0]
			name = dim[1]
			if id not in excluded and name[0]!='#':
				for i in range(len(name)):
					label=name[i]
					if label not in labels:
						labels+=[label]
						break
				result['id'].update({id:{'label':label}})
				result['label'].update({label:id})
	
				elems=self.Dimension(id).elements()
				i=0
				result['id'][id].update({'element':{}})
				result['id'][id].update({'index':{}})
				
				for elem in elems:
					if elem[6]!=4:
						result['id'][id]['element'].update({elem[0]:i})
						result['id'][id]['index'].update({i:elem[0]})
						i+=1
				result['id'][id].update({'range':i+1})
		#end of function suite
		return result
	
	def cube_labels(self, excluded=[]):
		#beginning of function suite
		"This function returns list of IndexedBase objects for the database dimensions"
		cubes=self.cubes()
		result={'id':{},'label':{}}
		labels=[]
		#for cube in cubes:
		for cube in cubes:
			id = cube[0]
			name = cube[1]
			if id not in excluded and name[0]!='#':
				id = cube[0]
				names = cube[1].split('_')
				name = names[0]
				subscripts=''
				
				if len(names)>1:
					subscripts='^'
					for n in names[1:]:
						subscripts+= n[0].upper()

				for i in range(len(name)):
					label=name[i].upper()+subscripts
					if label not in labels:
						labels+=[label]
						break
				result['id'].update({id:label})
				result['label'].update({label:id})
		#end of function suite
		return result

	#end of database class suite



class dimension(user):
	"""This is a dimension manipulator"""
	#beginning of class suite

	#def init
	def __init__(self, dimension=default["dimension"], database=default["database"], user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.dimension=dimension

	#api requests:
	def clear(self, dimension=None, database=None):
		"""Function clears a dimension\nPositional arguments: dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["clear"](dimension, database, self.getsid(), self.host, self.port)

	def create(self, new_name, database=None, **keywords):
		"""Function creates a new dimension\nPositional arguments: new_name, database=None\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["dimension"]["create"](new_name, database, self.getsid(), self.host, self.port, **keywords)

	def cubes(self, dimension=None, database=None, **keywords):
		"""Function returns the list of cubes using a dimension\nPositional arguments: dimension=None, database=None\nKeyword arguments: show_normal, show_system, show_attribute, show_info, show_gputype\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["cubes"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, dimension=None, database=None):
		"""Function deletes a dimension\nPositional arguments: dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["destroy"](dimension, database, self.getsid(), self.host, self.port)

	def element(self, position, dimension=None, database=None):
		"""Function returns one element at a given position\nPositional arguments: position, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["element"](position, dimension, database, self.getsid(), self.host, self.port)

	def elements(self, dimension=None, database=None, **keywords):
		"""Function returns the list of elements\nPositional arguments: dimension=None, database=None\nKeyword arguments: parent, limit\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["elements"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	def info(self, dimension=None, database=None):
		"""Function returns dimension info\nPositional arguments: dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["info"](dimension, database, self.getsid(), self.host, self.port)

	def rename(self, new_name, dimension=None, database=None):
		"""Function renames a dimension\nPositional arguments: new_name, dimension=None, database=None\nKeyword arguments: None
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["rename"](new_name, dimension, database, self.getsid(), self.host, self.port)
		
	def dfilter(self, cube, area, mode, dimension=None, database=None, **keywords):
		"""Function filters dimension elements\nPositional arguments: cube, area, mode, dimension=None, database=None\nKeyword arguments: condition, values\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["dimension"]["dfilter"](cube, area, mode, dimension, database, self.getsid(), self.host, self.port, **keywords)
		
	#The following functions create class objects:
	def Element(self, element=default["element"], dimension=None, database=None):
		"""Function creates element class object"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return element(element, dimension, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)
	
	#The following functions create sympy class objects:
	def Idx(self):
		"This function returns Idx object of a dimension in a db"
		#beginning of function suite
		name= self.info()[0][1]
		result=[]
		for element in self.elements():
			if element[6]!=4:
				result+=[element]
		i = Idx('i', dimension_length)
		#end of function suite
		return

	#The following functions are dimension tools:
	def dictionary(self, dimension=None, database=None, **keywords):
		"This function returns dictionary of dimension elements"
		#beginning of function suite
		dimension = dimension or self.dimension
		database = database or self.database
		elements=self.elements(dimension, database, **keywords)
		result={}
		result['ids']={}
		result['names']={}
		for element in elements:
			result['ids'][element[0]]=element[1]
			result['names'][element[1]]=element[0]
		#end of function suite
		return result
	
	def alias_list(self, dimension=None, database=None):
		"This function returns aliases names for the dimension"
		#beginning of function suite
		dimension = dimension or self.dimension
		database = database or self.database
		dict_db=self.Database(database).dictionary(show_attribute=1)
		dim_name=dict_db['dims']['ids'][dimension]
		alias_dim_name='#_'+dim_name+'_'
		alias_dim_id=dict_db['dims']['names'][alias_dim_name]
		alias_dim_dict=self.dictionary(alias_dim_id, database)
		if 'Alias' not in alias_dim_dict['names']:
			raise Exception('No aliases for Dim: '+dim_name)
		else:
			alias_id=alias_dim_dict['names']['Alias']
			elements=self.elements(alias_dim_id, database, parent=alias_id)
			result={}
			result['ids']={}
			result['names']={}
			for element in elements:
				result['ids'][element[0]]=element[1]
				result['names'][element[1]]=element[0]
		return result
		#end of function suite
	
	def alias_dict(self, alias, dimension=None, database=None):
		"This function returns element-alias dictionary for the dimension"
		#beginning of function suite
		dimension = dimension or self.dimension
		database = database or self.database
		if alias not in self.alias_list(dimension, database)['names']:
			raise Exception('Alias: '+alias+' not in Alias list')
		else:
			dict_db=self.Database(database).dictionary(show_attribute=1)
			dim_name=dict_db['dims']['ids'][dimension]
			alias_dim_name='#_'+dim_name+'_'
			alias_dim_id=dict_db['dims']['names'][alias_dim_name]
			alias_dim_dict=self.dictionary(alias_dim_id, database)
			alias_id=alias_dim_dict['names'][alias]
			alias_cub_name='#_'+dim_name
			alias_cub_id=dict_db['cubes']['names'][alias_cub_name]
			c=cell(None, alias_cub_id, database)
			n=c.Nda({alias_dim_id:[alias_id]})
			result={}
			result['ids']={}
			result['names']={}
			for element in self.elements(dimension, database):
				name=n.subnda({dimension:[element[0]]}).data
				result['ids'][element[0]]=name
				result['names'][element[1]]=name
		#end of function suite
		return result
	
	#end of element class suite

class element(user):
	"""This is an element manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, element=default["element"], dimension=default["dimension"], database=default["database"], user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.dimension=dimension
		self.element=element

	#api requests:
	def append(self, children, element=None, dimension=None, database=None, **keywords):
		"""Function appends the children of an consolidated element\nPositional arguments: children, element=None, dimension=None, database=None\nKeyword arguments: weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["append"](children, element, dimension, database, self.getsid(), self.host, self.port, **keywords)

	def create(self, new_name, type, dimension=None, database=None, **keywords):
		"""Function creates an element\nPositional arguments: new_name, type, dimension=None, database=None\nKeyword arguments: children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["create"](new_name, type, dimension, database, self.getsid(), self.host, self.port, **keywords)

	def create_bulk(self, name_elements, dimension=None, database=None, **keywords):
		"""Function creates elements\nPositional arguments: name_elements, dimension=None, database=None\nKeyword arguments: type, types, children, name_children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["create_bulk"](name_elements, dimension, database, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, element=None, dimension=None, database=None):
		"""Function deletes an element\nPositional arguments: element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["destroy"](element, dimension, database, self.getsid(), self.host, self.port)

	def destroy_bulk(self, dimension=None, database=None, **keywords):
		"""Function delete list of elements\nPositional arguments: dimension=None, database=None\nKeyword arguments: elements, name_elements\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["destroy_bulk"](dimension, database, self.getsid(), self.host, self.port, **keywords)
		
	def info(self, element=None, dimension=None, database=None):
		"""Function returns element info\nPositional arguments: element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["info"](element, dimension, database, self.getsid(), self.host, self.port)

	def move(self, position, element=None, dimension=None, database=None):
		"""Function changes position of an element\nPositional arguments: position, element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["move"](position, element, dimension, database, self.getsid(), self.host, self.port)

	def rename(self, new_name, element=None, dimension=None, database=None):
		"""Function renames an element\nPositional arguments: new_name, element=None, dimension=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		element = element or self.element
		#end of function suite
		return query["element"]["rename"](new_name, element, dimension, database, self.getsid(), self.host, self.port)

	def replace(self, dimension=None, database=None, **keywords):
		"""Function creates or updates an element\nPositional arguments: dimension=None, database=None\nKeyword arguments: element, name_element, type, children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["replace"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	def replace_bulk(self, dimension=None, database=None, **keywords):
		"""Function creates or updates list of elements\nPositional arguments: dimension=None, database=None\nKeyword arguments: elements, name_elements, type, children, weights\n
		"""
		#beginning of function suite
		database = database or self.database
		dimension = dimension or self.dimension
		#end of function suite
		return query["element"]["replace_bulk"](dimension, database, self.getsid(), self.host, self.port, **keywords)

	#The following functions create class objects:
	#end of element class suite

class cube(user):
	"""This is a cube manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, cube=default["cube"], database=default["database"], user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.cube=cube

	#api requests:
	def clear(self, cube=None, database=None, **keywords):
		"""Function clears a cube\nPositional arguments: cube=None, database=None\nKeyword arguments: area, complete\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["clear"](cube, database, self.getsid(), self.host, self.port, **keywords)

	def commit(self, lock, cube=None, database=None):
		"""Function commits changes of a locked cube area\nPositional arguments: lock, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["commit"](lock, cube, database, self.getsid(), self.host, self.port)

	def create(self, new_name, dimensions, database=None, **keywords):
		"""Function creates a cube\nPositional arguments: new_name, dimensions, database=None\nKeyword arguments: type (0=normal (default), 3=user info)\n
		"""
		#beginning of function suite
		database = database or self.database
		#end of function suite
		return query["cube"]["create"](new_name, dimensions, database, self.getsid(), self.host, self.port, **keywords)

	def destroy(self, cube=None, database=None):
		"""Function deletes a cube\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["destroy"](cube, database, self.getsid(), self.host, self.port)

	def info(self, cube=None, database=None):
		"""Function returns cube info\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)

	def load(self, cube=None, database=None):
		"""Function loads cube\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["load"](cube, database, self.getsid(), self.host, self.port)

	def lock(self, area, cube=None, database=None):
		"""Function locks a cube area\nPositional arguments: area, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["lock"](area, cube, database, self.getsid(), self.host, self.port)

	def locks(self, cube=None, database=None):
		"""Function lists the locked cube areas\nPositional arguments: , cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["locks"](cube, database, self.getsid(), self.host, self.port)

	def rename(self, new_name, cube=None, database=None):
		"""Function renames a cube\nPositional arguments: new_name, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["rename"](new_name, cube, database, self.getsid(), self.host, self.port)
		
	def rollback(self, lock, steps, cube=None, database=None):
		"""Function rollbacks changes of a locked cube area\nPositional arguments: lock, steps, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["rollback"](lock, steps, cube, database, self.getsid(), self.host, self.port)

	def rules(self, use_identifier=0, cube=None, database=None):
		"""Function lists the rules for a cube\nPositional arguments: use_identifier=0, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["rules"](use_identifier, cube, database, self.getsid(), self.host, self.port)

	def save(self, cube=None, database=None):
		"""Function saves cube data to disk\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["save"](cube, database, self.getsid(), self.host, self.port)

	def unload(self, cube=None, database=None):
		"""Function unloads cube data from memory\nPositional arguments: cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cube"]["unload"](cube, database, self.getsid(), self.host, self.port)
		
	#The following functions create class objects:
	def Cell(self, path=default["path"], cube=None, database=None):
		"""Function creates cell class object"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return cell(path, cube, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)

	def Rules(self, rule=default["rule"], cube=None, database=None):
		"""Function creates rules class object"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return rules(rule, cube, database, self.user, self.password, self.sid, self.timeinit, self.timeleft, self.host, self.port)
	
	#The following functions create sympy class objects:
	def IndexedBase(self):
		"This function returns IndexedBase for the cube"
		#beginning of function suite
		name=''
		for word in (self.info()[0][1]).split('_'):
			result+=word[0].upper()+word[1:].lower()
		result = IndexedBase(name)
		#end of function suite
		return result
	
	def Idxs(self):
		"This function returns list of Idx objects for the cube dimensions"
		#beginning of function suite
		#for dim in self.info()[0][3]:
		
		#name=''
		for word in (self.info()[0][1]).split('_'):
			result+=word[0].upper()+word[1:].lower()
		result = IndexedBase(name)
		#end of function suite
		return result

	def Indexed(db, cube):
		"This function returns Indexed object for the cube"
		#beginning of function suite
		M = IndexedBase('M')
		i, j = symbols('i j', cls=Idx)
		#end of function suite
		return M[i, j]

	#end of cube class suite

class cell(user):
	"""This is a cube manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, path=default["path"], cube=default["cube"], database=default["database"], user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.cube=cube
		self.path=path

	#api requests:
	def area(self, area, show_rule, show_lock_info, cube=None, database=None):
		"""Function shows values of cube cells\nPositional arguments: area, show_rule, show_lock_info, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["area"](area, show_rule, show_lock_info, cube, database, self.getsid(), self.host, self.port)

	def copy(self, path_to, path=None, cube=None, database=None, **keywords):
		"""Function copies a cell path to an other cell path\nPositional arguments: path_to, path=None, cube=None, database=None\nKeyword arguments: value\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["copy"](path_to, path, cube, database, self.getsid(), self.host, self.port, **keywords)

	def drillthrough(self, mode, path=None, cube=None, database=None, **keywords):
		"""Function retrieves detailed data for a cube cell\nPositional arguments: mode, path=None, cube=None, database=None\nKeyword arguments: value\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["drillthrough"](mode, path, cube, database, self.getsid(), self.host, self.port, **keywords)
		
	def export(self, cube=None, database=None, **keywords):
		"""Function exports values of cube cells\nPositional arguments: cube=None, database=None\nKeyword arguments: blocksize, path, area, condition, use_rules, base_only, skip_empty, type\n
		"""
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["export"](cube, database, self.getsid(), self.host, self.port, **keywords)
		
	def goalseek(self, path=None, cube=None, database=None, **keywords):
		"""Function puts value into cell and calculates values for sister cells in order to parents remain unchanged\nPositional arguments: path=None, cube=None, database=None\nKeyword arguments: value\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["goalseek"](path, cube, database, self.getsid(), self.host, self.port, **keywords)

	def replace(self, value, path=None, cube=None, database=None, **keywords):
		"""Function sets or changes the value of cube cell\nPositional arguments: path=None, cube=None, database=None\nKeyword arguments: add, splash, event_processor\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["replace"](value, path, cube, database, self.getsid(), self.host, self.port, **keywords)

	def replace_bulk(self, paths, values, cube=None, database=None, **keywords):
		"""Function sets or changes the value of cube cells\nPositional arguments: cube=None, database=None\nKeyword arguments: add, splash, event_processor\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["replace_bulk"](paths, values, cube, database, self.getsid(), self.host, self.port, **keywords)

	def value(self, show_rule, show_lock_info, path=None, cube=None, database=None):
		"""Function returns the value of a cube cell\nPositional arguments: show_rule, show_lock_info, path=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		path = path or self.path
		#end of function suite
		return query["cell"]["value"](show_rule, show_lock_info, path, cube, database, self.getsid(), self.host, self.port)

	def values(self, paths, show_rule, show_lock_info, cube=None, database=None):
		"""Function returns the values of a cube cells\nPositional arguments: show_rule, show_lock_info, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["cell"]["values"](paths, show_rule, show_lock_info, cube, database, self.getsid(), self.host, self.port)

	#The following functions are cell tools

	def extract(self, conditions={}, output=None, params=[0,1,1,0], cube=None, database=None):
		"This function returns values of database cube for {dim_id:[elems_ids]}\nParams: [use_rules, base_only, skip_empty, type]\nOutput: list of [type, exists, value, path] lists"
		#beginning of function suite
		
		database = database or self.database
		cube = cube or self.cube
		
		dimensions = query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)[0][3]
		
		area=arealize(conditions, dimensions)
		
		result=self.export(cube, database, area=area, use_rules=params[0], base_only=params[1], skip_empty=params[2], type=params[3])
		
		while result[-1][0]<result[-1][1]:
			for item in result[:-1]:
				item=sublist(item, output)
				if len(item)==1:
					yield item[0]
				else:
					yield item
			result=self.export(cube, database, area=area, use_rules=params[0], base_only=params[1], skip_empty=params[2], type=params[3], path=','.join(strlist(result[-2][3])))

		if result[-1][0]>=result[-1][1]:
			for item in result[:-1]:
				item=sublist(item, output)
				if len(item)==1:
					yield item[0]
				else:
					yield item
		#end of function suite

	
	#The following functions create class objects:
	def Tensor(self, conditions={}, params=[0,1,1,0], cube=None, database=None):
		"This function returns nda class object"
		#beginning of function suite
		
		database = database or self.database
		cube = cube or self.cube
		dimensions = query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)[0][3]
		
		#Формируются генераторы данных куба
		typevalue=self.extract(conditions, [0,2], params, cube, database)
		coord=self.extract(conditions, [3], params, cube, database)
		valuecoord=self.extract(conditions, [2,3], params, cube, database)
		
		#Формируется метрика куба
		metrics = meter(typevalue, coord, valuecoord, dimensions)
		
		#К метрике куба добавляются словари:
		metrics["dictionary"]={}
		
		s_dict_iter=self.Server().dictionary()
		s_dict={"db":self.Server().dictionary()}
		for item in s_dict_iter["ids"]:
			if item != database:
				del s_dict["db"]["ids"][item]
		for item in s_dict_iter["names"]:
			if s_dict_iter["names"][item] != database:
				del s_dict["db"]["names"][item]
		
		db_dict_iter=self.Database().dictionary()
		db_dict=self.Database().dictionary()
		for item in db_dict_iter["dims"]["ids"]:
			if item not in dimensions:
				del db_dict["dims"]["ids"][item]
		for item in db_dict_iter["dims"]["names"]:
			if db_dict_iter["dims"]["names"][item] not in dimensions:
				del db_dict["dims"]["names"][item]
		for item in db_dict_iter["cubes"]["ids"]:
			if item != cube:
				del db_dict["cubes"]["ids"][item]
		for item in db_dict_iter["cubes"]["names"]:
			if db_dict_iter["cubes"]["names"][item] != cube:
				del db_dict["cubes"]["names"][item]
	
		el_dict={"elems":{}}
		for dim in metrics["dims"]:
			el_dict["elems"][dim]=self.Dimension(dim).dictionary()

		metrics["dictionary"].update(s_dict)
		metrics["dictionary"].update(db_dict)
		metrics["dictionary"].update(el_dict)
		
		#Функция возвращает экземпляр класса nda
		return nda(database, cube, conditions, params, metrics["dims"], metrics["dims_nda"], metrics["elems"], metrics["elems_filled"], metrics["length"], metrics["width"], metrics["width_nda"], metrics["shape"], metrics["shape_nda"], metrics["type"], metrics["null"], metrics["data"], metrics["dictionary"])
		
	
	def Nda(self, conditions={}, params=[0,1,1,0], cube=None, database=None):
		"This function returns nda class object"
		#beginning of function suite
		
		database = database or self.database
		cube = cube or self.cube
		dimensions = query["cube"]["info"](cube, database, self.getsid(), self.host, self.port)[0][3]
		
		#Формируются генераторы данных куба
		typevalue=self.extract(conditions, [0,2], params, cube, database)
		coord=self.extract(conditions, [3], params, cube, database)
		valuecoord=self.extract(conditions, [2,3], params, cube, database)
		
		#Формируется метрика куба
		metrics = meter(typevalue, coord, valuecoord, dimensions)
		
		#К метрике куба добавляются словари:
		metrics["dictionary"]={}
		
		s_dict_iter=self.Server().dictionary()
		s_dict={"db":self.Server().dictionary()}
		for item in s_dict_iter["ids"]:
			if item != database:
				del s_dict["db"]["ids"][item]
		for item in s_dict_iter["names"]:
			if s_dict_iter["names"][item] != database:
				del s_dict["db"]["names"][item]
		
		db_dict_iter=self.Database().dictionary()
		db_dict=self.Database().dictionary()
		for item in db_dict_iter["dims"]["ids"]:
			if item not in dimensions:
				del db_dict["dims"]["ids"][item]
		for item in db_dict_iter["dims"]["names"]:
			if db_dict_iter["dims"]["names"][item] not in dimensions:
				del db_dict["dims"]["names"][item]
		for item in db_dict_iter["cubes"]["ids"]:
			if item != cube:
				del db_dict["cubes"]["ids"][item]
		for item in db_dict_iter["cubes"]["names"]:
			if db_dict_iter["cubes"]["names"][item] != cube:
				del db_dict["cubes"]["names"][item]
				
		el_dict={"elems":{}}
		for dim in metrics["dims"]:
			el_dict["elems"][dim]=self.Dimension(dim).dictionary()
		
		metrics["dictionary"].update(s_dict)
		metrics["dictionary"].update(db_dict)
		metrics["dictionary"].update(el_dict)

		#Функция возвращает экземпляр класса nda
		return nda(database, cube, conditions, params, metrics["dims"], metrics["dims_nda"], metrics["elems"], metrics["elems_filled"], metrics["length"], metrics["width"], metrics["width_nda"], metrics["shape"], metrics["shape_nda"], metrics["type"], metrics["null"], metrics["data"], metrics["dictionary"])
	
	def Lol(self, columns, rows, filters, conditions, aliases, zeros=True, names=True, empty=None):
		"This function generates list of lists from cube cells"
		#beginning of function suite

		#Для каждого измерения-фильтра:
		for item in filters:
			#Если в условиях ему не соответствует лист длиной в один элемент
			if not(type(conditions[item])==list and len(conditions[item])==1):
				#Вызывается исключение
				raise Exception("Dim: "+str(item)+". Condition for the filter dimension must be a list of one element")
		if names:
			columns_names = columns
			columns = []
			rows_names = rows
			rows = []
			filters_names = filters
			filters = []
			conditions_names = deepcopy(conditions)
			conditions = {}
			aliases_names = deepcopy(aliases)
			aliases = {}
			
			db_dict = self.Database().dictionary()
			
			for column_name in columns_names:
				columns += [db_dict['dims']['names'][column_name]]
			
			for row_name in rows_names:
				rows += [db_dict['dims']['names'][row_name]]
			
			for filters_name in filters_names:
				filters += [db_dict['dims']['names'][filters_name]]
			
			for item in conditions_names:
				dim = db_dict['dims']['names'][item]
				dim_dict = self.Dimension(dim).dictionary()
				conditions[dim]=[]
				for subitem in conditions_names[item]:
					conditions[dim]+=[dim_dict['names'][subitem]]
			
			for item in aliases_names:
				dim = db_dict['dims']['names'][item]
				aliases[dim]=[]
				for subitem in aliases_names[item]:
					aliases[dim]+=[subitem]

		else:
			columns_names = []
			rows_names = []
			filters_names = []
			conditions_names = {}
			aliases_names = {}
			
			db_dict = self.Database().dictionary()
			
			for column in columns:
				columns_names += [db_dict['dims']['ids'][column]]
			
			for row in rows:
				rows_names += [db_dict['dims']['ids'][row]]
			
			for filter in filters:
				filters_names += [db_dict['dims']['ids'][filter]]
			
			for dim in conditions:
				dim_dict = self.Dimension(dim).dictionary()
				dim_name = db_dict['dims']['ids'][dim]
				conditions_names[dim_name]=[]
				for item in conditions[dim]:
					conditions_names[dim_name]+=[dim_dict['ids'][item]]
			
			for dim in aliases:
				dim_name = db_dict['dims']['ids'][dim]
				aliases_names[dim_name]=[]
				for item in aliases[dim]:
					aliases_names[dim_name]+=[item]

		db_dict=self.Database().dictionary()
		#Для каждого измерения в словаре алиасов:
		for dim in aliases:
			for alias in aliases[dim]:
				if alias and alias not in self.Dimension(dim).alias_list()['names']:
					raise Exception('Alias: '+alias+' not in alias list for Dim: '+str(dim))


		#Создается объект класса nda
		n=self.Nda(conditions, [0,0,1,0]).subnda()
		#print(list(n.dictionary['elems'][17]['ids']))
		#Проверяется все ли измерения распределены между колонками, строками и фильтром
		#Для каждого измерения объекта nda
		for dim in n.dims:
			#Если измерения нет в сумме списков колонок, строк и фильтра
			if dim not in columns + rows + filters:
				#Вызывается исключение
				raise Exception("Dim: "+str(dim)+". Dimension neither in columns nor rows nor filters list")
		
		#Если подавление нулей истинно 
		if zeros:
			#переменной helems присваивается словарь элементов
			helems=n.elems
		#Иначе
		else:
			#переменной helems присваивается словарь заполненных элементов
			helems=n.elems_filled
			
		#Формируется словарь шагов для колонок
		cpaces=pacecounter(columns, helems)
		#Формируется словарь элементов колонок
		celems=headfiller(columns, helems, cpaces)
		#Переменной clen присваивается длина списка измерений-колонок
		clen=len(columns)
		
		#Определяется дополнительная длина алиасов для колонок (строк)
		calen=0
		for column in columns:
			if column in aliases:
				calen-=1
				for alias in aliases[column]:
					calen+=1
		
		#Формируется словарь шагов для строк
		rpaces=pacecounter(rows, helems)
		#Формируется словарь элементов строк
		relems=headfiller(rows, helems, rpaces)
		#Переменной rlen присваивается длина списка измерений-строк
		rlen=len(rows)
		
		#Определяется дополнительная длина алиасов для колонок (строк)
		ralen=0
		for row in rows:
			if row in aliases:
				ralen-=1
				for alias in aliases[row]:
					ralen+=1
		
		flen=len(filters)
		
		#Создается пустой список результат
		result=[]
		
		#I. Добавляются заголовки колонок
		#Для каждого измерения-колонки:
		for column in columns:
			#Создается пустой временный список:
			temp=[]
			#В него добавляется список пустых значений соответствующий заголовкам строк
			temp+=[empty]*(rlen+ralen)
			#Для каждого элемента в списке элементов измерения-колонки:
			for elem in celems[column]:
				#Во временный список добавляется имя элемента
				temp+=[n.dictionary['elems'][column]['ids'][elem]]
			
			#Если измерение-колонка в словаре алиасов:
			if column in aliases:
				newtemp=[]
				for alias in aliases[column]:
					if not alias:
						newtemp+=[temp]
					else:
						alias_dict=self.Dimension(column).alias_dict(alias)['names']
						aliastemp=[]
						for i in temp:
							if i:
								aliastemp+=[alias_dict[i]]
							else:
								aliastemp+=[i]
						newtemp+=[aliastemp]
				result+=newtemp
			else:
				result+=[temp]
		
		#II. Добавляются заголовки строк и значения таблицы
		#Для каждого номера строки значений:
		for x in range(rpaces['len']):
			#Создается пустой временный список
			temp=[]
			#Для каждого номера колонки таблицы:
			for y in range(rlen+cpaces['len']):
				#Если номер колонки в ряду номеров строк:
				if y in range(rlen):
					#Во временный список добавляется заголовок соответствующей строки
					temp+=[n.dictionary['elems'][rows[y]]['ids'][relems[rows[y]][x]]]
					if rows[y] in aliases:
						newtemp=[]
						alias_dict=self.Dimension(rows[y]).alias_dict(alias)['ids']
						for alias in aliases[rows[y]]:
							if not alias:
								newtemp+=temp
							else:
								newtemp+=[alias_dict[relems[rows[y]][x]]]
						temp=newtemp
				#Иначе
				else:
					#Создается пустой словарь координат соответствующей ячейки куба
					cell={}
					#Для каждого измерения-колонки
					for column in columns:
						#В словарь добавляется соответствующий номер элемента
						cell[column]=[celems[column][y-rlen]]
					#Для каждого измерения-строки
					for row in rows:
						#В словарь добавляется соответствующий номер элемента
						cell[row]=[relems[row][x]]
					#Во временный список добавляется значение ячейки куба
					temp+=[n.subnda(cell).data]
			#В результат добавляется временный список
			result+=[temp]
		#Функция возвращает класс list of list (lol)
		return lol(self.database, self.cube, columns, columns_names, cpaces, clen+calen, rows, rows_names, rpaces, rlen+ralen, filters, filters_names, flen, conditions, conditions_names, aliases, aliases_names, zeros, n.type, result)

	#end of cell class suite

class event(host):
	"""This is an event manipulator"""
	#beginning of class suite
	
	#def init
	def __init__(self, host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(host, port)
		#child methods

	#api requests:
	def begin(self, sid, source, event):
		"""Function starts an event\nPositional arguments: sid, source, event\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["event"]["begin"](sid, source, event, self.host, self.port)

	def end(self, sid):
		"""Function ends an event\nPositional arguments: sid\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["event"]["end"](sid, self.host, self.port)

	#other groups api requests:
	#The following functions create class objects:

	#end of event class suite

class rules(user):
	"""This is a rules manipulator"""
	#beginning of class suite

	#def init
	def __init__(self, rule=default["rule"], cube=default["cube"], database=default["database"], user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
		self.database=database
		self.cube=cube
		self.rule=rule

	#api requests:
	def create(self, definition, activate, external_identifier, comment, use_identifier, cube=None, database=None):
		"""Function creates a new enterprise rule for a cube\nPositional arguments: definition, activate, external_identifier, comment, use_identifier, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		#end of function suite
		return query["rules"]["create"](definition, activate, external_identifier, comment, use_identifier, cube, database, self.getsid(), self.host, self.port)
		
	def destroy(self, rule=None, cube=None, database=None):
		"""Function removes an enterprise rule from a cube\nPositional arguments: rule=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		rule = rule or self.rule
		#end of function suite
		return query["rules"]["destroy"](rule, cube, database, self.getsid(), self.host, self.port)

	def functions(self):
		"""Function lists available functions\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["rules"]["functions"](self.getsid(), self.host, self.port)

	def info(self, use_identifier, rule=None, cube=None, database=None):
		"""Function returns information about a defined rule\nPositional arguments: use_identifier, rule=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		rule = rule or self.rule
		#end of function suite
		return query["rules"]["info"](use_identifier, rule, cube, database, self.getsid(), self.host, self.port)

	def modify(self, definition, activate, external_identifier, comment, use_identifier, rule=None, cube=None, database=None):
		"""Function modifies an enterprise rule for a cube\nPositional arguments: definition, activate, external_identifier, comment, use_identifier, rule=None, cube=None, database=None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		database = database or self.database
		cube = cube or self.cube
		rule = rule or self.rule
		#end of function suite
		return query["rules"]["modify"](definition, activate, external_identifier, comment, use_identifier, rule, cube, database, self.getsid(), self.host, self.port)
		
	def parse(self, definition, **keywords):
		"""Function parse an enterprise rule\nPositional arguments: definition\nKeyword arguments: database, cube, functions\n
		"""
		#beginning of function suite
		#end of function suite
		return query["rules"]["parse"](definition, self.getsid(), self.host, self.port, **keywords)

	#other groups api requests:
    #extended functions:
	def symbolize(self):
		"""Function returns symbolic expression for the rules instance\nPositional arguments: ?definition?\nKeyword arguments: ?database, cube, functions?\n
		"""
		#beginning of function suite
		#end of function suite
		return

	#The following functions create class objects:
	
	#end of rule class suite

class svs(user):
	"""This is a svs manipulator"""
	#beginning of class suite
	
	#import functions from rules module
	
	
	#def init
	def __init__(self, user=default["user"], password=default["password"], sid=default["sid"], timeinit=default["timeinit"], timeleft=default["timeleft"], host=default["host"], port=default["port"]):
		#parent init
		super(__class__, self).__init__(user, password, sid, timeinit, timeleft, host, port)
		#child methods
	
	#api requests:
	def info(self):
		"""Function returns information about Supervision Server\nPositional arguments: None\nKeyword arguments: None\n
		"""
		#beginning of function suite
		#end of function suite
		return query["svs"]["info"](self.getsid(), self.host, self.port)

	#other groups api requests:
	#The following functions create class objects:

	#end of svs class suite


class tensor:
	"This is a manipulator for tensor from olap"
	#beginning of class suite
	def __init__(self, database, cube, conditions, params, dims, dims_nda, elems, elems_filled, length, width, width_nda, shape, shape_nda, type, null, data, dictionary):
		self.database=database
		self.cube=cube
		self.conditions=conditions
		self.params=params
		self.dims=dims
		self.dims_nda=dims_nda
		self.elems=elems
		self.elems_filled=elems_filled
		self.length=length
		self.width=width
		self.width_nda=width_nda
		self.shape=shape
		self.shape_nda=shape_nda
		self.type=type
		self.null=null
		self.data=data
		self.dictionary=dictionary
	
	def subtensor(self, new_con={}, reduce=True):
		"This function returns new nda object where conditions={dim:elems} is satisfied and single element dimension is reduced if reduce is True"
		#beginning of function suite
		#Создается словарь новых атрибутов в соответствии с условиями выборки
		new=subdata(new_con, deepcopy(self.conditions), deepcopy(self.dims), deepcopy(self.dims_nda), deepcopy(self.elems), self.null, deepcopy(self.data), reduce)
		#print(self.dims)
		#Создается новый объект класса nda с измененными атрибутами
		result=nda(self.database, self.cube, new["conditions"], self.params, self.dims, new["dims_nda"], new["elems"], new["elems_filled"], self.length, self.width, new["width_nda"], new["shape"], new["shape_nda"], self.type, self.null, new["data"], self.dictionary)
		#end of function suite
		#Функция возвращает новый объект nda
		return result

	def extract():
		"This function returns values from olap for the given Indexed object and ranges of its indices"
		#beginning of function suite
		#end of function suite
		return

	def nda():
		"This function returns nda from olap for the given Indexed object and ranges of its indices"
		#beginning of function suite
		#end of function suite
		return

	def lol():
		"This function returns lol (list of lists) from olap for the given Indexed object and ranges of its indices"
		#beginning of function suite
		#end of function suite
		return

#Slice or dice should be chosen (slicing or dicing) and dictionaries bugs. n.Nda() inherits last call conditions


#end of nda class suite


class nda:
	"This is a manipulator for nda from olap"
	#beginning of class suite
	def __init__(self, database, cube, conditions, params, dims, dims_nda, elems, elems_filled, length, width, width_nda, shape, shape_nda, type, null, data, dictionary):
		self.database=database
		self.cube=cube
		self.conditions=conditions
		self.params=params
		self.dims=dims
		self.dims_nda=dims_nda
		self.elems=elems
		self.elems_filled=elems_filled
		self.length=length
		self.width=width
		self.width_nda=width_nda
		self.shape=shape
		self.shape_nda=shape_nda
		self.type=type
		self.null=null
		self.data=data
		self.dictionary=dictionary
		
	def subnda(self, new_con={}, reduce=True):
		"This function returns new nda object where conditions={dim:elems} is satisfied and single element dimension is reduced if reduce is True"
		#beginning of function suite
		#Создается словарь новых атрибутов в соответствии с условиями выборки
		new=subdata(new_con, deepcopy(self.conditions), deepcopy(self.dims), deepcopy(self.dims_nda), deepcopy(self.elems), self.null, deepcopy(self.data), reduce)
		#print(self.dims)
		#Создается новый объект класса nda с измененными атрибутами
		result=nda(self.database, self.cube, new["conditions"], self.params, self.dims, new["dims_nda"], new["elems"], new["elems_filled"], self.length, self.width, new["width_nda"], new["shape"], new["shape_nda"], self.type, self.null, new["data"], self.dictionary)
		#end of function suite
		#Функция возвращает новый объект nda
		return result
		
	#Slice or dice should be chosen (slicing or dicing) and dictionaries bugs. n.Nda() inherits last call conditions
		
		
	#end of nda class suite
class lol:
	"This is a manipulator for list of list from olap"
	#beginning of class suite
	def __init__(self, database, cube, columns, columns_names, cpaces, clen, rows, rows_names, rpaces, rlen, filters, filters_names, flen, conditions, conditions_names, aliases, aliases_names, zeros, type, data):
		self.database=database
		self.cube=cube
		self.columns=columns
		self.columns_names=columns_names
		self.cpaces=cpaces
		self.clen=clen
		self.rows=rows
		self.rows_names=rows_names
		self.rpaces=rpaces
		self.rlen=rlen
		self.filters=filters
		self.filters_names=filters_names
		self.flen=flen
		self.conditions=conditions
		self.conditions_names=conditions_names
		self.aliases=aliases
		self.aliases_names=aliases_names
		self.zeros=zeros
		self.type=type
		self.data=data
	
	def supzcols(self):
		"This function removes columns with null values"
		#beginning of function suite
		#Создается пустой список номеров колонок для удаления
		dellist=[]
		#Для каждого номера колонки в области значений
		for x in range(self.rlen, len(self.data[0])):
			#Переменной temp присваивается нулевое значение
			temp=0
			#Дя каждой строки в области значений
			for row in self.data[self.clen:]:
				#Если self.type=1 (numeric)
				if self.type==1:
					#К переменной темп прибавляется значение ячейки
					temp+=row[x]
				#Иначе (string)
				else:
					#К переменной темп прибавляется длина значения ячейки
					temp+=len(row[x])
			#Если переменная temp равна нулю
			if temp==0:
				#Данный номер колонки добавляется в список колонок на удаление
				dellist+=[x]
		
		#Создается пустой словарь-отчет о подавлении нулевых колонок
		report={}
		for item in dellist:
			report[item]=[]
			for x in range(self.clen):
				report[item]+=[self.data[x][item]]

		#Создается пустой список результат
		result=[]
		#Для каждой строки в списке списков
		for row in self.data:
			#Создается временный список temp
			temp=[]
			#Для каждого номера колонки в таблице, исключая удаляемые номера:
			for z in [col for col in range(len(self.data[0])) if col not in dellist]:
				#Во временный список добавляется соответствующее значене из строки данных
				temp+=[row[z]]
			#В результирующий список добавляется список строка
			result+=[temp]
		#self.data присвается список result
		self.data=result
		#Функция возвращает отчет о подавлении нулевых колонок
		return report
	
	def supzrows(self):
		"This function removes rows with null values"
		#beginning of function suite
		#Создается пустой список номеров строк для удаления
		dellist=[]
		#Для каждой строки в области значений
		for row in self.data[self.clen:]:
			#Переменной temp присваивается нулевое значение
			temp=0
			#Для каждого номера колонки в области значений
			for col in row[self.rlen:]:
				#Если self.type=1 (numeric)
				if self.type==1:
					#К переменной темп прибавляется значение ячейки
					temp+=col
				#Иначе (string)
				else:
					#К переменной темп прибавляется длина значения ячейки
					temp+=len(col)
			#Если переменная temp равна нулю
			if temp==0:
				#Данный номер строки добавляется в список строк на удаление
				dellist+=[self.data.index(row)]
		
		#Создается пустой словарь-отчет о подавлении нулевых строк
		report={}
		for item in dellist:
			report[item]=[]
			for x in range(self.rlen):
				report[item]+=[self.data[item][x]]
		
		#Создается пустой список результат
		result=[]
		#Для каждого номера строки в таблице, исключая удаляемые номера:
		for z in [row for row in range(len(self.data)) if row not in dellist]:
			#В результирующий список добавляется список строка
			result+=[self.data[z]]
			
		#self.data присвается список result
		self.data=result
		#Функция возвращает отчет о подавлении нулевых колонок
		return report
	
	def wrapheads(self, width):
		"This function divide heads names into lines to fit width"
		#beginning of function suite
		result=self.data
		for x in range(self.clen):
			row=[]
			for item in self.data[x]:
				if item:
					rest=item
					temp=[]
					while len(rest)>width:
						if ' ' in rest and rest.index(' ')<=width:
							temp+=[rest[:rest.index(' ')]]
							rest=rest[rest.index(' ')+1:]
						else:
							temp+=[rest[:width-1]+'-']
							rest=rest[width-1:]
					temp+=[rest]
					temp='\n'.join(temp)
					row+=[temp]
				else:
					row+=[item]
			result[x]=row
		
		self.data=result

		for x in range(len(self.data)):
			for y in range(self.rlen):
				if self.data[x][y]:
					rest=self.data[x][y]
					temp=[]
					while len(rest)>width:
						if ' ' in rest and rest.index(' ')<=width:
							temp+=[rest[:rest.index(' ')]]
							rest=rest[rest.index(' ')+1:]
						else:
							temp+=[rest[:width-1]+'-']
							rest=rest[width-1:]
					temp+=[rest]
					temp='\n'.join(temp)
					self.data[x][y]=temp

		#end of function suite
		return
	
	def deldubheads(self):
		"This function replaces duplicated columns and rows names with None"
		#beginning of function suite
		for x in range(self.clen):
			temp=deepcopy(self.data[x])
			for y in range(self.rlen, len(temp)):
				if temp[y] and temp[y]==temp[y-1]:
					self.data[x][y]=None
		
		temp=deepcopy(self.data)
		for x in range(self.clen, len(self.data)):
			for y in range(self.rlen):
				if temp[x][y] and temp[x][y]==temp[x-1][y]:
					self.data[x][y]=None
		#end of function suite
		return
	
#	def pdfgen(self, path):
#		"This function generates pdf file from lol object"
#		#beginning of function suite
#
#		#end of function suite
#		return
#
#    def xlsgen(self, path):
#		"This function generates xls file from lol object"
#		#beginning of function suite
#		outbook = xlwt.Workbook()
#		outsheet = outbook.add_sheet('Sheet')
#		for x in range(self.flen):
#			#print(self.filters_names[x])
#			outsheet.write(x, 0, self.filters_names[x])
#			#print(self.conditions_names[self.filters_names[x]])
#			outsheet.write(x, 1, self.conditions_names[self.filters_names[x]][0])
#		for x in range(len(self.data)):
#			for y in range(len(self.data[0])):
#				outsheet.write(x+self.flen, y, self.data[x][y])
#		outbook.save(path)
#		#end of function suite
#		return